#include <iostream>
#include <unistd.h>
#include <stdio.h>

//进程状态的意义:方便OS快速判断进程,完成特定的功能,比如说调度
//进程状态本质是对进程的一种分类
//*************************************

//R运行状态(running):这种状态并不意味着进程一定是在运行中(不一定占有cpu),它表明进程要么是在运行中,要么是在运行队列等待中

//running_test

//int main()
//{
//    //一直在while里面循环,就会处于R状态
//    while(true);
//
//    return 0;
//}
//*****************************************

//S睡眠状态(sleeping):意味着进程在等待事件的完成
//{这里的睡眠有时候也叫做可中断睡眠(interruptible sleep),也可叫做浅度睡眠}
//换种说法就是,当进程完成某种任务时,任务条件不具备,需要进程进行等待
//比如说进程申请屏幕进行打印，那么屏幕在为其他进程打印，不能为我所用
//那么我的test_struct就进入等待队列,状态变为S+
//直到屏幕能为我所用,然后被唤醒

//那么因为很多进程都有这种需求,所以产生了等待队列
//那么cpu运行进程的时候,需要申请其他硬件的使用
//那么我们就把运行状态的test_struct(run_queue),放到等待队列中(wait_queue)
//这种状态被叫做挂起等待(阻塞)
//在等待队列中的test_struct如果获得其他硬件资源的使用,就会放到运行队列被cpu调度
//这个过程叫做唤醒进程
//注意:千万不要认为,进程只会等待cpu资源,进程也会等待其他硬件的资源

//test_sleeping
//int main()
//{
//    //因为cpu的处理速度比屏幕的响应速度快多了
//    //所以基本上这个进程都处于S+的状态
//    //很少的时间才是R+的状态
//    while(true)
//    {
//        std::cout << "刘坤yyds!!!" << std::endl;
//    }
//    return 0;
//}
//*********************************************

//D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep)
//在这个状态的进程通常会等待IO的结束
//不可中断，指的并不是CPU不响应外部硬件的中断，而是指进程不响应异步信号(kill)
//D状态存在的意义就在于，内核的某些处理流程是不能被打断的
//如果响应异步信号，程序的执行流程中就会被插入一段用于处理异步信号的流程
//在进程对某些硬件进行操作时
//比如进程调用read系统调用对某个设备文件进行读操作
//而read系统调用最终执行到对应设备驱动的代码,并与对应的物理设备进行交互，
//可能需要使用TASK_UNINTERRUPTIBLE状态对进程进行保护
//以避免进程与设备交互的过程被打断，造成设备陷入不可控的状态。

//注意:一般情况下,进程申请大部分系统资源没有被满足的情况下,进入S状态
//而如果是申请磁盘或者网络资源没有被满足的情况下,则会进入D状态
//也就是说进程在内核中某些不能被信号打断
//例如对某些硬件设备进行操作时刻（等待磁盘io,等待网络io等等）

//这种状态不太好看见,这里就不做测试了
//*************************************************

//T停止状态(stopped):可以通过发送SIGSTOP信号给进程来停止(T)进程
//这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行
//t追踪状态(tracing stop):当进程正在被追踪时,就会处于这种特殊的状态
//“正在被跟踪”指的是进程暂停下来，等对进行进操作
//比如在gdb中对被跟踪的进程下一个断点
//进程在断点处停下来的时候就处于TASK_TRACED状态。
//**************************************************************

//如何让进程进入T状态?
//kill:送出一个特定的信号给一个pid的进程,而这个进程根据信号而做出动作
//kill -l:列出所有可用的信号的名称
//kill -19(SIGSTOP) pid:暂停进程编号为pid的进程
//kill -18(SIGCONT) pid:恢复进程编号为pid的进程

//执行以上代码,会发现一个事情,我进程暂停恢复后,并不会看见继续运行的现象
//所以这里引入一个进程状态+的概念,进程状态+表示,进程运行在前台
//可以看到进程运行的现象
//如果只有进程状态,表示进程运行在后台,不能看到进程运行的现象

//所以我们来理清一下上面暂停回复的过程
//首先进程运行在前台,所以是R+的状态
//然后执行kill -19 pid,进程进入T的状态,这里已经变为后台进程了
//最后执行kill -18 pid,进程恢复到R的状态,只不过这里变为后台进程了
//这样情况下,如果你要关掉这个进程,需要kill -9(SIGKILL) pid,指定关闭

//test_stopped
//int main()
//{
//    while(true);
//    return 0;
//}
//*************************************************
//
//Z僵死状态(Zombies)
//进程在退出的过程中，处于TASK_DEAD状态。
//在这个退出过程中，进程占有的所有资源将被回收
//除了task_struct中的结构（以及少数资源）以外
//于是进程就只剩下的task_struct的这么个空壳，故称为僵尸
//之所以保留的是task_struct，是因为task_struct中的里面保存了进程的退出码
//以及一些统计信息。而其父进程很可能会关心这些信息。

//僵死状态是一种比较特殊得状态
//当进程退出并且父进程没有读取到子进程退出得返回代码时就会产生僵尸进程
//僵尸进程会以终止状态保持在进程表里,并且会一直等待父进程读取退出状态代码
//所以,只要子进程退出,父进程还在运行,但是父进程没有读取子进程得状态
//子进程就进入Z状态

//僵尸进程的危害:
//1.因为进程的退出状态必须被维持下去,因为它要告诉关心它的的进程(父进程)
//你交给我的任务,我办理的怎么样了,但是父进程一直不读取的话
//那么子进程就会一直处于Z状态
//2.退出状态本身需要用数据结构来维护,也属于进程的基本信息
//所以被保护在task_struct(PCB)中,只要Z状态一直不退出,PCB就会一直维护
//3.所以,父进程如果一直不回收子进程的task_struct,就会造成内存资源的浪费
//而且因为这些PCB会对进程表进行占位,如果Z进程太多了,就会导致,不能创建新的进程

//test_zombies
int main()
{
    pid_t id = fork();

    if (id > 0)
    {
        std::cout << "I am the parent.I am sleeping : " << 
        getpid() << std::endl;
        sleep(5);
    }
    else if(id == 0)
    {
        std::cout << "I am the child. I am zombie : " <<
        getpid() << std::endl;
        sleep(1);
    }
    else 
    {
        perror("fork");
        return 1;
    }
    return 0;
}
//配合自动检测脚本观察
//while : ; do ps axj | head -1 && ps axj | grep process_status | grep -v grep; sleep 1; 
//echo "#############################################################################"; done
//*************************************************

//孤儿进程
//如果父进程比子进程优先退出,那么谁来给子进程收尸?
//当父进程退出的时候，会将它的所有子进程都托管给别的进程
//（使之成为别的进程的子进程）。托管给谁呢？
//可能是退出进程所在进程组的下一个进程（如果存在的话）
//或者是1号进程。所以每个进程，每时每刻都有父进程存在除非它是1号进程。

//PID为1的进程，又称初始化进程.linux系统启动后
//第一个被创建的用户态进程就是初始化进程它有两项使命：
//1.执行系统初始化脚本，创建一系列的进程（它们都是初始化进程的子孙）;
//2.在一个死循环中等待其子进程的退出事件
//并调用waitid系统调用来完成“收尸工作
//初始化进程不会被暂停，也不会被杀死（这是由内来保证的）
//它在等待子进程退出的过程中处于TASK_INTERRUPTIBLE状态
//“收尸”过程中则处于TASK_RUNNING状态。

//test_orphan
//int main()
//{
//    pid_t id = fork();
//
//    if (id > 0)
//    {
//        std::cout << "I am the parent.I am sleeping : " << 
//        getpid() << " ppid:" << getppid() << std::endl;
//        sleep(1);
//    }
//    else if(id == 0)
//    {
//        std::cout << "I am the child. I am orphan : " <<
//        getpid() << " ppid:" << getppid() << std::endl;
//        sleep(30);
//    }
//    else 
//    {
//        perror("fork");
//        return 1;
//    }
//    return 0;
//}
//************************************************

//死亡状态X(dead):这个状态只是一个返回状态,你不会在任务列表中看到这个状态
//同时这个状态,会销毁进程的task_struct

